<?php

namespace app\admin\controller;

use app\common\controller\Backend;
use think\Db;
use think\Request;
use think\Log;

/**
 * Ysapi控制器
 *
 * @icon fa fa-gears
 */
class Ysapi extends Backend
{
    
    /**
     * Ysapi模型对象
     * @var \app\admin\model\Ysapi
     */
    protected $model = null;
    // 权限
    protected $noNeedLogin = ['*'];
    protected $noNeedRight = ['*'];

    public function _initialize()
    {
        parent::_initialize();

        if (request()->method() === 'OPTIONS') {
            $allowOrigin = 'https://dev002.gxyushengwenhua.com'; // 前端域名
            // 输出 CORS 头
            header("Access-Control-Allow-Origin: {$allowOrigin}");
            header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
            header("Access-Control-Allow-Credentials: true");
            header("Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With");
            header("Access-Control-Max-Age: 86400");
            // 预检请求无需返回内容，直接结束
            http_response_code(204);
            exit;
        }

        $this->model = new \app\admin\model\Ysapi;
    }
    
    /**
     * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法
     * 因此在当前控制器中可不用编写增删改查的代码
     */
    
    /**
     * 申请退款
     * 
     * @param Request $request
     * @return mixed
     */
    public function applyRefund(Request $request)
    {
        // 获取参数
        if ($this->request->isOptions()) {
            header("HTTP/1.1 200 OK");
            exit();
        }
        $order_id = $request->param('order_id');
        $order_id = $order_id?:$request->param('apply_item_id');
        $refund_fee = $request->param('refund_fee');
        $refund_reason = $request->param('refund_reason', '');
        
        // 验证参数
        if (empty($order_id)) {
            return $this->error('订单ID不能为空');
        }
        
        // 如果退款金额为空，则设置为全额退款
        $order = Db::name('fa_order')->alias("order")->join('eb_apply_form_item', 'order.id = eb_apply_form_item.order_id','left')->field('order.*,eb_apply_form_item.id as apply_item_id')->where('order.id', $order_id)->find();
                // 查询订单信息
        if (!$order) {
            return $this->error('订单不存在');
        }
        
        if (empty($refund_fee)) {
            $refund_fee = $order['amount'];
        } elseif (!is_numeric($refund_fee)) {
            return $this->error('退款金额必须为数字');
        }
        

        
        // 检查订单状态
        if ($order['status'] == 4) {
            $refund = Db::name('refund')->where('order_id', $order_id)->find();
            if($refund){
                $msg= $refund['status'] == 1 ? '订单已退款。<p>退款单号:<br>'.$refund['out_refund_no']."<br>时间:".date('Y-m-d H:i:s',$refund['update_time'])."<br>微信退款金额:".$refund['refund_fee'] : '订单退款中';
                header("Content-Type: application/json");
                echo json_encode(['code' => 200, 'msg' => $msg, 'data' => $refund]);
                exit;

            }
        }
        
        if ($order['status'] != 1) {
            return $this->error('订单状态不允许退款');
        }
        
        // 检查退款金额
        if ($refund_fee > $order['amount']) {
            return $this->error('退款金额不能大于订单金额');
        }
        
        // 如果提供了报名项目ID，则查询报名项目信息
        if (!empty($apply_item_id)) {
            $applyItem = Db::name('eb_apply_form_item')->where('id', $apply_item_id)->find();
            if (!$applyItem) {
                return $this->error('报名项目不存在');
            }
            
            // 检查报名项目状态
            if ($applyItem['pay_status'] == 4) {
                $refund = Db::name('refund')->where('order_id', $order_id)->find();
                if($refund){
                    return $this->success('报名项目已退款', $refund);
                }
            }
            
            // 检查报名项目是否属于该订单
            if ($applyItem['order_id'] != $order_id) {
                return $this->error('报名项目不属于该订单');
            }
        }

        $refundData= db::name('fa_refund')->where('order_id',$order['id'])->find();

        
        // 生成退款单号
        if($refundData==null) {
            $refund_no = 'REFUND' . date('YmdHis') . mt_rand(1000, 9999);

            // 创建退款记录
            $refundData = [
                'user_id' => $order['user_id'],
                'order_id' => $order_id,
                'refund_no' => $refund_no,
                'refund_fee' => $refund_fee,
                'fail_reason' => $refund_reason,
                'status' => 0, // 退款处理中
                'create_time' => time(),
                'update_time' => time(),
            ];
            // 如果提供了报名项目ID，则添加到退款记录中
            if(!empty($apply_item_id)){
                $refundData['apply_item_id'] = $apply_item_id;
            }

            if(empty($refundData['apply_item_id'])&&!empty($order['apply_item_id'])){
                $refundData['apply_item_id'] = $order['apply_item_id'];
            }
            $refundId = Db::name('refund')->insertGetId($refundData);
        }
        $apply_item_id=$order['apply_id'];
        db::name('fa_refund')->where('order_id',$order['id'])->whereNull('apply_item_id')->update(['refund_no'=>$apply_item_id]);
        $refundData= db::name('fa_refund')->where('order_id',$order['id'])->find();
        $refundId = $refundData['id'];

        


        
        try {
            // 查询微信退款状态
            $refundStatus = $this->queryWechatRefundStatus($refundData['refund_no']);
            
            if(isset($refundStatus['refund_status']) && $refundStatus['refund_status'] == 'SUCCESS'){
                $this->finishRefund($refundId, $refundStatus,$order_id,$apply_item_id,$refund_fee);
                
                return $this->success('退款成功', $refundStatus);
            } 
            else if(isset($refundStatus['refund_status']) && $refundStatus['refund_status'] == 'PROCESSING'){
                Db::name('refund')->where('id', $refundId)->update([
                    'status' => 3, // 退款处理中
                    'refund_id' => $refundStatus['refund_id'] ?? '', // 微信退款单号
                    'update_time' => time(),
                    'refund_status' => $refundStatus['status'], // 退款状态
                    'create_time' => strtotime($refundStatus['create_time']), // 微信退款创建时间
                    'out_refund_no' => $refundStatus['out_refund_no'] ?? '', // 商户退款单号
                    'out_trade_no' => $refundStatus['out_trade_no'] ?? '', // 商户订单号
                    'user_received_account' => $refundStatus['user_received_account'] ?? '', // 用户退款收款账户
                ]);
                
                return $this->success('申请已经成功，正在退款的过程中...', $refundStatus);
            } 
            else if(isset($refundStatus['refund_status']) && $refundStatus['refund_status'] == 'FAILED'){
                Db::name('refund')->where('id', $refundId)->update([
                    'status' => 2, // 退款失败
                    'update_time' => time(),
                    'refund_status' => $refundStatus['refund_status'], // 退款状态
                    'create_time' => strtotime($refundStatus['create_time']), // 微信退款创建时间
                    'out_refund_no' => $refundStatus['out_refund_no'] ?? '', // 商户退款单号
                    'out_trade_no' => $refundStatus['out_trade_no'] ?? '', // 商户订单号
                    'refund_id' => $refundStatus['refund_id'] ?? '', // 微信退款单号
                    'user_received_account' => $refundStatus['user_received_account'] ?? '', // 用户退款收款账户
                ]);
                
                return $this->success('退款申请已经提交，退款金额将在1-3个工作日内原路返回', $refundStatus);
            } 
            else{
                // 调用微信退款API
                $result = $this->processWechatRefund(
                    $order['pay_channel_id'], // 微信支付交易订单号
                    $refundData['refund_no'], // 商户退款单号
                    $order['amount'], // 订单金额
                    $refund_fee // 退款金额
                );
                $refundStatus = $this->queryWechatRefundStatus($refundData['refund_no']);
                if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS'){
                    $this->finishRefund($refundId, $refundStatus,$order_id,$apply_item_id,$refund_fee);
                }
                return $this->success('退款申请已提交，请等待处理', [
                    'refund_id' => $refundId,
                    'refund_no' => $refund_no,
                    'status' => 0,
                    'status_text' => '退款处理中'
                ]);
            }
            
        } catch (\Exception $e) {
            // 处理特定错误情况：订单已退款
            if($e->getMessage() == '退款申请失败: 退款申请失败: 订单已退款' || $e->getMessage() == '[INVALID_REQUEST] 订单已全额退款'){
                Db::name('refund')->where('id', $refundId)->update([
                    'status' => 1, // 退款成功
                    'refund_id' => $refundData['id'] ?? '', // 微信退款单号
                    'update_time' => time(),
                    'refund_status' => '订单已退款', // 退款状态
                    'create_time' => time(), // 微信退款创建时间
                    'out_refund_no' => $refundData['refund_no'] ?? '', // 商户退款单号
                    'out_trade_no' => $order['order_sn'] ?? '', // 商户订单号
                ]);
                
                // 更新订单状态
                Db::name('order')->where('id', $order_id)->update([
                    'status' => 4, // 已退款
                    'pay_status' => 4, // 已退款
                    'refund_time' => time(),
                    'refund_status' => 'SUCCESS',
                    'refund_amount' => $refund_fee,
                ]);
                
                // 更新报名项目状态
                if(!empty($apply_item_id)){
                    Db::name('eb_apply_form_item')->where('id', $apply_item_id)->update([
                        'pay_status' => 4, // 退款成功
                        'status' => 0, // 退款成功
                    ]);
                }
                
                return $this->success('已退过款', $refundData);
            } 
            else{
                // 再次查询退款状态
                $refundStatus = $this->queryWechatRefundStatus($refundData['refund_no']);
                
                if($refundStatus['refund_status'] === 'SUCCESS'){
                    $this->finishRefund($refundId, $refundStatus,$order_id,$apply_item_id,$refund_fee);
                    return $this->success('此订单已经成功退过款', $refundStatus);
                } 
                else {
                    Db::name('refund')->where('id', $refundId)->update([
                        'status' => 2, // 退款失败
                        'fail_reason' => $e->getMessage(),
                        'update_time' => time(),
                    ]);
                    
                    return $this->error('退款申请失败: ' . $e->getMessage(), null, 500);
                }
            }
        }
    }

    private function finishRefund($refundId, $refundStatus,$order_id,$apply_item_id,$refund_fee){
        Db::name('refund')->where('id', $refundId)->update([
            'status' => 1, // 退款成功
            'refund_id' => $refundStatus['refund_id'] ?? '', // 微信退款单号
            'update_time' => time(),
            'refund_status' => $refundStatus['refund_status'], // 退款状态
            'create_time' => strtotime($refundStatus['create_time']), // 微信退款创建时间
            'out_refund_no' => $refundStatus['out_refund_no'] ?? '', // 商户退款单号
            'out_trade_no' => $refundStatus['out_trade_no'] ?? '', // 商户订单号
            'user_received_account' => $refundStatus['user_received_account'] ?? '', // 用户退款收款账户
        ]);

        // 更新订单状态
        Db::name('order')->where('id', $order_id)->update([
            'status' => 4, // 已退款
            'pay_status' => 4, // 已退款
            'refund_id' => $refundStatus['refund_id'],
            'refund_time' => time(),
            'refund_status' => 'SUCCESS',
            'refund_amount' => $refund_fee,
        ]);

        // 更新报名项目状态
        if(!empty($apply_item_id)){
            Db::name('eb_apply_form_item')->where('id', $apply_item_id)->update([
                'pay_status' => 4, // 退款成功
                'status' => 0, // 退款成功
            ]);
        }
        return true;
    }
    
    /**
     * 处理微信退款
     * 
     * @param string $transactionId 微信支付订单号
     * @param string $refundNo 商户退款单号
     * @param float $totalFee 订单金额
     * @param float $refundFee 退款金额
     * @return array 退款结果
     */
    private function processWechatRefund($transactionId, $refundNo, $totalFee, $refundFee) {
        // 加载微信支付配置
        $config = \think\Config::get('wechat.pay');
        if (empty($config)) {
            throw new \Exception('微信支付配置未找到');
        }
        
        // 退款请求URL
        $url = 'https://api.mch.weixin.qq.com/v3/refund/domestic/refunds';
        
        // 构造请求数据
        $data = [
            'transaction_id' => $transactionId,
            'out_refund_no' => $refundNo,
            'amount' => [
                'refund' => intval($refundFee * 100), // 退款金额，单位：分
                'total' => intval($totalFee * 100), // 订单金额，单位：分
                'currency' => 'CNY'
            ]
        ];
        
        // 添加退款原因（如果有）
        if (!empty($this->request->param('refund_reason'))) {
            $data['reason'] = $this->request->param('refund_reason');
        }
        
        // 发送请求
        $result = $this->requestWechatRefund($data);
        
        return $result;
    }
    
    /**
     * 发送微信退款请求
     * 
     * @param array $data 请求数据
     * @return array 响应结果
     */
    private function requestWechatRefund($data) {
        // 加载微信支付配置
        $config = \think\Config::get('wechat.pay');
        if (empty($config)) {
            throw new \Exception('微信支付配置未找到');
        }
        
        // 退款请求URL
        $url = 'https://api.mch.weixin.qq.com/v3/refund/domestic/refunds';
        
        $body = $data ? json_encode($data, JSON_UNESCAPED_UNICODE) : '';
        $auth = $this->buildRefundAuth('POST', $url, $body, $config);
        
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_HTTPHEADER => [
                'Accept: application/json',
                'Content-Type: application/json',
                'User-Agent: FastAdmin/WeChatPay',
                'Authorization: ' . $auth
            ]
        ]);
        
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
        
        $response = curl_exec($ch);
        $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);
        
        if ($error) {
            throw new \Exception("CURL Error: " . $error);
        }
        
        $result = json_decode($response, true);
        
        // 微信退款查询接口可能返回200以外的成功状态码，我们只在明确的错误状态码时抛出异常
        if ($status >= 400) {
            $message = isset($result['message']) ? $result['message'] : '微信退款接口请求失败';
            $code = isset($result['code']) ? $result['code'] : 'UNKNOWN_ERROR';
            throw new \Exception("[$code] $message");
        }
        
        return $result;
    }
    
    /**
     * 构造退款请求的Authorization
     * 
     * @param string $method HTTP方法
     * @param string $url 请求URL
     * @param string $body 请求体
     * @param array $config 微信支付配置
     * @return string Authorization头
     */
    private function buildRefundAuth($method, $url, $body, $config) {
        $timestamp = time();
        $nonce = uniqid();
        $urlParts = parse_url($url);
        $canonicalUrl = ($urlParts['path'] ?? '/') . (isset($urlParts['query']) ? '?' . $urlParts['query'] : '');
        
        // 对于GET请求，body应该为空字符串而不是null
        if ($method === 'GET') {
            $body = '';
        }
        
        $message = $method . "\n" .
            $canonicalUrl . "\n" .
            $timestamp . "\n" .
            $nonce . "\n" .
            $body . "\n";
        
        $signature = $this->generateRefundSign($message, $config['key_path']);
        
        return sprintf(
            'WECHATPAY2-SHA256-RSA2048 mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
            $config['mchid'],
            $nonce,
            $timestamp,
            $config['serial_no'],
            $signature
        );
    }
    
    /**
     * 生成退款请求签名
     * 
     * @param string $message 签名串
     * @param string $keyPath 商户API私钥路径
     * @return string 签名
     */
    private function generateRefundSign($message, $keyPath) {
        $privateKey = openssl_pkey_get_private(file_get_contents($keyPath));
        if (!$privateKey) {
            throw new \Exception('无法加载商户API私钥');
        }
        
        $signature = '';
        if (!openssl_sign($message, $signature, $privateKey, OPENSSL_ALGO_SHA256)) {
            throw new \Exception('签名生成失败: ' . openssl_error_string());
        }
        
        return base64_encode($signature);
    }

    /**
     * 查询微信退款状态
     * 
     * @param string $refundNo 商户退款单号
     * @return array 退款状态信息
     */
    private function queryWechatRefundStatus($refundNo) {
        try {
            // 加载微信支付配置
            $config = \think\Config::get('wechat.pay');
            if (empty($config)) {
                throw new \Exception('微信支付配置未找到');
            }
            
            // 查询退款请求URL
            $url = 'https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/' . $refundNo;
            
            // 发送查询请求
            $result = $this->requestWechatRefundQuery($url, $config);
            
            // 处理返回结果
            $status = [
                'refund_status' => $result['status'] ?? 'UNKNOWN', // 退款状态
                'refund_id' => $result['refund_id'] ?? '', // 微信退款单号
                'out_refund_no' => $result['out_refund_no'] ?? '', // 商户退款单号
                'out_trade_no' => $result['out_trade_no'] ?? '', // 商户订单号
                'create_time' => $result['create_time'] ?? '', // 退款创建时间
                'user_received_account' => $result['user_received_account'] ?? '', // 用户退款收款账户
                'success_time' => $result['success_time'] ?? '', // 退款成功时间
            ];
            
            // 如果有退款金额信息
            if (isset($result['amount'])) {
                $status['total'] = $result['amount']['total'] ?? 0; // 订单总金额
                $status['refund'] = $result['amount']['refund'] ?? 0; // 退款金额
                $status['payer_total'] = $result['amount']['payer_total'] ?? 0; // 用户支付金额
                $status['payer_refund'] = $result['amount']['payer_refund'] ?? 0; // 用户退款金额
            }
            
            return $status;
        } catch (\Exception $e) {
            return [
                'refund_status' => 'ERROR',
                'message' => $e->getMessage()
            ];
        }
    }
    
    /**
     * 发送微信退款查询请求
     * 
     * @param string $url 请求URL
     * @param array $config 微信支付配置
     * @return array 响应结果
     */
    private function requestWechatRefundQuery($url, $config) {
        $body = '';
        $auth = $this->buildRefundAuth('GET', $url, $body, $config);
        
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_HTTPHEADER => [
                'Accept: application/json',
                'Content-Type: application/json',
                'User-Agent: FastAdmin/WeChatPay',
                'Authorization: ' . $auth
            ]
        ]);
        
        $response = curl_exec($ch);
        $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);
        
        if ($error) {
            throw new \Exception("CURL Error: " . $error);
        }
        
        $result = json_decode($response, true);
        
        // 微信退款查询接口可能返回200以外的成功状态码，我们只在明确的错误状态码时抛出异常
        if ($status >= 400) {
            $message = isset($result['message']) ? $result['message'] : '微信退款查询接口请求失败';
            $code = isset($result['code']) ? $result['code'] : 'UNKNOWN_ERROR';
            throw new \Exception("[$code] $message");
        }
        
        return $result;
    }
}